package com.slliver.orderservice.service.impl;

import com.slliver.commonmodel.order.Order;
import com.slliver.commonmodel.product.Product;
import com.slliver.dubboservice.api.ProductServiceApi;
import com.slliver.orderservice.feign.ProductFeignService;
import com.slliver.orderservice.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
//import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Override
    public Order saveOrderByRestTemplate(Long userId, Long productId) {
        Product product = this.getProductByRestTemplate(productId);
        return saveOrder(userId, product, "restTemplate");
    }

    /**
     * 基于编程时的负责均衡的写法
     */
    @Override
    public Order saveOrderWithLoadBalancerByRestTemplate(Long userId, Long productId) {
        Product product = this.getProductWithLoadBalancerByRestTemplate(productId);
        return saveOrder(userId, product, "restTemplate");
    }

    /**
     * 基于注解式的负责均衡的写法，注意需要在配置类的RestTemplate上加上注解LoadBalanced
     * 可以使用这种方式进行开发
     */
    @Override
    public Order saveOrderWithAnnotationLoadBalancerByRestTemplate(Long userId, Long productId) {
        Product product = this.getProductWithAnnotationLoadBalancerByRestTemplate(productId);
        return saveOrder(userId, product, "restTemplate");
    }

    @Override
    public Order saveOrderByOpenFeign(Long userId, Long productId) {
        Product product = this.getProductByOpenFeign(productId);
        return saveOrder(userId, product, "openFeign");
    }

    @Override
    public Order saveOrderByDubbo(Long userId, Long productId) {
//        Product product = this.getProductByDubbo(productId);
//        return saveOrder(userId, product, "dubbo");

        return null;
    }

    private Order saveOrder(Long userId, Product product, String getDataType) {
        Order order = new Order();
        order.setId(1L);
        // 商品总金额
        order.setTotalAmout(product.getPrice().multiply(new BigDecimal(product.getNum())));
        order.setUserId(userId);
        order.setNickName("TOMCAT");
        order.setAddress("辽宁省大连市金州区");
        // 商品列表
        order.setProductList(Arrays.asList(product));
        System.out.println(getMessage(getDataType));
        return order;
    }

    @Autowired
    private DiscoveryClient discoveryClient;
    @Autowired
    private RestTemplate restTemplate;

    private Product getProductByRestTemplate(Long productId) {
        String serviceId = "product-service";
        String serviceUrl = getServerUrl(serviceId, productId);
        // 给远程的商品服务发送请求
        Product product = restTemplate.getForObject(serviceUrl, Product.class);
        return product;
    }

    // 带有负载均衡的机制去请求商品服务(轮训机制)
    private Product getProductWithLoadBalancerByRestTemplate(Long productId) {
        String serviceId = "product-service";
        String serviceUrl = getServerUrlByLoadBalancer(serviceId, productId);
        // 给远程的商品服务发送请求
        Product product = restTemplate.getForObject(serviceUrl, Product.class);
        return product;
    }

    // 使用注解式的负载均衡
    private Product getProductWithAnnotationLoadBalancerByRestTemplate(Long productId) {
        String serviceId = "product-service";
        String serviceUrl = getServerUrlWithAnnotationLoadBalancer(serviceId, productId);
        // 给远程的商品服务发送请求
        Product product = restTemplate.getForObject(serviceUrl, Product.class);
        return product;
    }

    @Autowired
    private ProductFeignService productFeignService;

    private Product getProductByOpenFeign(Long productId) {
        String serviceId = "product-service";
        String serviceUrl = getServerUrl(serviceId, productId);
        Product product = productFeignService.getProduct(productId);
        return product;
    }

    /**
     @Reference(version="1.0.0") private ProductServiceApi productServiceApi;

     private Product getProductByDubbo(Long productId) {
     return productServiceApi.getProductById(productId);
     }
     **/


    /**
     * 获取请求商品服务的url信息
     */
    private String getServerUrl(String serviceId, Long productId) {
        // 1、获取到商品服务所在的机器信息(ip+端口)
        List<ServiceInstance> instanceList = discoveryClient.getInstances(serviceId);
        if (CollectionUtils.isEmpty(instanceList)) {
            return "";
        }
        ServiceInstance instance = instanceList.get(0);
        // 拼接远程的url地址：http://192.168.3.8:8082/product/1001
        String serviceUrl = "http://" + instance.getHost() + ":" + instance.getPort() + "/api/product/" + productId;
        log.info("远程请求路径:{}", serviceUrl);
        return serviceUrl;
    }

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    private String getServerUrlByLoadBalancer(String serviceId, Long productId) {
        // 获取买一个服务的实例，使用了负载均衡技术自动获取
        ServiceInstance instance = loadBalancerClient.choose(serviceId);
        // 拼接远程的url地址：http://192.168.3.8:8082/product/1001
        String serviceUrl = "http://" + instance.getHost() + ":" + instance.getPort() + "/api/product/" + productId;
        log.info("使用负载均衡的方式去远程请求商品服务的完整请求路径:{}", serviceUrl);
        return serviceUrl;
    }

    private String getServerUrlWithAnnotationLoadBalancer(String serviceId, Long productId) {
        // 获取买一个服务的实例，使用了负载均衡技术自动获取
        ServiceInstance instance = loadBalancerClient.choose(serviceId);
        // 拼接远程的url地址：http://192.168.3.8:8082/product/1001替换成http://商品服务的实例/product/1001即http://product-service/product/1001
        String serviceUrl = "http://" + serviceId + "/api/product/" + productId;
        log.info("使用注解负载均衡的方式去远程请求商品服务的完整请求路径:{}", serviceUrl);
        return serviceUrl;
    }

    private String getMessage(String getDataType) {
        String msg = "";
        if (Objects.equals("restTemplate", getDataType)) {
            msg = "使用restTemplate方式获取商品信息创建订单成功...";
        } else if (Objects.equals("openFeign", getDataType)) {
            msg = "使用openFeign方式获取商品信息创建订单成功...";
        } else if (Objects.equals("dubbo", getDataType)) {
            msg = "使用dubbo方式获取商品信息创建订单成功...";
        } else {
            msg = "使用非法方式获取商品信息创建订单成功...";
        }
        return msg;
    }
}
